package com.tsfyun.common.base.exception;

import cn.hutool.core.util.StrUtil;
import com.tsfyun.common.base.config.properties.NoticeProperties;
import com.tsfyun.common.base.dto.Result;
import com.tsfyun.common.base.enums.ResultCodeEnum;
import com.tsfyun.common.base.help.DingTalkNoticeUtil;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.validator.ValidatorUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Objects;

/**
 * =
 * 统一异常处理
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @Autowired
    private NoticeProperties noticeProperties;

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result defaultErrorHandler(HttpServletRequest request, HttpServletResponse response, Exception e) throws Exception {
        logger.error(StrUtil.format("请求地址【{}】,统一异常：",request.getRequestURL()), e);
        List<String> dingdingUrl = noticeProperties.getDingdingUrl();
        switch (e.getClass().getName()) {
            case "org.springframework.web.HttpRequestMethodNotSupportedException":
                DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                return Result.error("405", "方法不被允许");
            case "org.springframework.web.bind.MissingServletRequestParameterException":
            case "org.springframework.http.converter.HttpMessageNotReadableException":
                DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                return Result.error("415", "请求参数错误");
            case "org.springframework.validation.BindException":
                DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                org.springframework.validation.BindException bindException = (org.springframework.validation.BindException) e;
                List<ObjectError> fieldErrors = bindException.getBindingResult().getAllErrors();
                if (fieldErrors != null && fieldErrors.size() > 0) {
                    ObjectError objectError = ValidatorUtils.getPermanentError(fieldErrors);
                    return Result.error(objectError.getDefaultMessage());
                }
                return Result.error("请核对您提交的数据是否正确");
            case "org.springframework.web.bind.MethodArgumentNotValidException":
                org.springframework.web.bind.MethodArgumentNotValidException notValidException = (org.springframework.web.bind.MethodArgumentNotValidException) e;
                List<ObjectError> allErrors = notValidException.getBindingResult().getAllErrors();
                if (allErrors != null && allErrors.size() > 0) {
                    ObjectError objectError = ValidatorUtils.getPermanentError(allErrors);
                    String errorMsg = objectError.getDefaultMessage();
                    if (objectError instanceof FieldError) {
                        FieldError fieldError = (FieldError) objectError;
                        String errorField = fieldError.getField();
                        if (errorField.contains("[") && errorField.contains("].")) {
                            //取列表异常序号
                            try {
                                int errorIndex = Integer.parseInt(errorField.substring(errorField.indexOf("[") + 1, errorField.indexOf("]")));
                                errorMsg = "第" + (errorIndex + 1) + "行" + errorMsg;
                            } catch (Exception ex) {
                                logger.error("解析异常获取行号异常", ex);
                            }
                        }
                    }
                    return Result.error(errorMsg);
                }
                return Result.error("请核对您提交的数据是否正确");
            case "org.springframework.dao.DataIntegrityViolationException":
                DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                logger.error("数据保存异常：", e);
                if(e.getMessage().contains("Data too long")) {
                    return Result.error("填写的内容长度过长");
                } else {
                    return Result.error("保存失败，请检查数据合法性");
                }
            case "org.springframework.security.access.AccessDeniedException":
                DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                return Result.error("403", "您无此访问权限");
            case "org.springframework.web.multipart.MaxUploadSizeExceededException":
                return Result.error("您上传的文件内容过大");
            case "org.springframework.web.multipart.support.MissingServletRequestPartException":
                return Result.error("请您上传文件");
            case "com.tsfyun.common.base.exception.ClientException":
                return Result.error(e.getMessage());
            case "com.tsfyun.common.base.exception.ServiceException":
                ServiceException serviceException = (ServiceException) e;
                if (!Objects.equals(ResultCodeEnum.FAIL.getCode(), serviceException.getCode())) {
                    return Result.error(serviceException.getCode(), serviceException.getMessage());
                }
                return Result.error(e.getMessage());
            case "java.lang.IllegalStateException":
                if (StringUtils.isNotEmpty(e.getMessage()) && e.getMessage().contains("You do not own lock at")) {
                    DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                    return Result.error("服务拥挤，请稍后再试");
                } else if (StringUtils.isNotEmpty(e.getMessage()) && e.getMessage().contains("No instances available for")) {
                    DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                    return Result.error("服务开小差了，马上就好，请您稍后再试");
                } else {
                    DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                    return Result.error(e.getMessage());
                }
            case "java.lang.RuntimeException":
                if (StringUtils.isNotEmpty(e.getMessage()) && e.getMessage().contains("com.netflix.client.ClientException: Load balancer does not have available server for client")) {
                    DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                    return Result.error("服务开小差了，马上就好，请您稍后再试");
                } else {
                    DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                    return Result.error("请求异常,请稍后重试");
                }
            case "org.springframework.web.bind.MissingRequestHeaderException":
                return Result.error("请求参数错误");
            case "java.io.IOException":
                if(StringUtils.isNotEmpty(e.getMessage()) && e.getMessage().contains("Broken pipe")) {
                    logger.info("进来IOException Broken pipe");
                    return null;
                } else {
                    return Result.error("请求异常,请稍后重试");
                }
            case "org.apache.catalina.connector.ClientAbortException":
                if(StringUtils.isNotEmpty(e.getMessage()) && e.getMessage().contains("Broken pipe")) {
                    logger.info("进来ClientAbortException Broken pipe");
                    return null;
                } else {
                    return Result.error("请求异常,请稍后重试");
                }
            case "org.springframework.dao.DuplicateKeyException":
                if (StringUtils.isNotEmpty(e.getMessage()) && e.getMessage().contains("Duplicate entry")
                     && e.getMessage().contains("for key")) {
                    String duplicateKey = e.getMessage().substring(e.getMessage().indexOf("Duplicate entry") + 15,e.getMessage().indexOf("for key"));
                    DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                    return Result.error(StrUtil.format("数据【{}】重复，请修改后再提交",duplicateKey));
                } else {
                    DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                    return Result.error("数据重复，请修改后再提交");
                }
            default:
                DingTalkNoticeUtil.send2DingDing(request, e,dingdingUrl);
                return Result.error("请求异常,请稍后重试");
        }
    }



}